package org.wk.account.service;

import com.alibaba.fastjson.JSONObject;
import com.google.common.base.Strings;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.joda.time.LocalDate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.wk.account.dao.SubAccountDao;
import org.wk.account.dao.ling.SubAccountLingAdminUpdateBillDao;
import org.wk.account.dao.ling.SubAccountLingDao;
import org.wk.account.dao.ling.SubAccountLingExchangeCNYDao;
import org.wk.account.dao.ling.SubAccountLingSeqDao;
import org.wk.account.domain.SubAccount;
import org.wk.account.domain.ling.SubAccountLing;
import org.wk.account.domain.ling.SubAccountLingAdminUpdateBill;
import org.wk.account.domain.ling.SubAccountLingExchangeCNY;
import org.wk.account.domain.ling.SubAccountLingSeq;
import org.wk.account.enums.*;
import org.wk.account.view.LingExchangeCNYVo;
import org.wk.common.dao.SmsDao;
import org.wk.common.domain.Sms;
import org.wk.common.enums.SmsCodeType;
import org.wk.common.jpush.PushService;
import org.wk.core.common.tool.ExcelUtils;
import org.wk.core.common.tool.RegexUtils;
import org.wk.core.common.view.PageVo;
import org.wk.core.common.view.ResponseVo;
import org.wk.core.db.tool.WebUtils;
import org.wk.core.web.exception.GeneralException;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.io.File;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @author TangShenShen
 * @Description:鲸灵服务实现类
 * @date 2018/5/189:52
 */
@Service
public class SubAccountLingServiceImpl implements SubAccountLingService {
    @Autowired
    private SubAccountLingSeqDao subAccountLingSeqDao;

    @Autowired
    private SubAccountDao subAccountDao;

    @Autowired
    private SubAccountLingDao subAccountLingDao;

    @Autowired
    private SubAccountLingExchangeCNYDao lingExchangeCNYDao;
    @Autowired
    private SubAccountLingAdminUpdateBillDao subAccountLingAdminUpdateBillDao;

    @Autowired
    private SmsDao smsDao;
    @Autowired
    private PushService pushService;

    @Override
    public Page<SubAccountLingSeq> findSeqByCriteria(Integer page, Integer size, SubAccountLingSeq subAccountLingSeq) {
        Sort sort = Sort.by(Sort.Direction.DESC,"createTime");
        Page<SubAccountLingSeq> lingSeqPage = subAccountLingSeqDao.findAll(new Specification<SubAccountLingSeq>() {
            @Override
            public Predicate toPredicate(Root<SubAccountLingSeq> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {

                List<Predicate> list = new ArrayList<Predicate>();
                if(null!=subAccountLingSeq.getUserId()&&!"".equals(subAccountLingSeq.getUserId())){
                    list.add(criteriaBuilder.equal(root.get("userId").as(String.class), subAccountLingSeq.getUserId()));
                }
                Predicate[] p = new Predicate[list.size()];
                return criteriaBuilder.and(list.toArray(p));
            }
        }, PageRequest.of(page,size,sort));
        return lingSeqPage;
    }

    /**
     * @Description PC获取鲸灵提现列表
     * @param params
     * @author ZhaoPing'an
     * @Date 2018/7/2 14:52
     */
    @Override
    public PageVo findExchangeCNYListPage(Map<String, Object> params) {
        String realName = (String)params.get("realName");
        String mobileNumber = (String)params.get("mobileNumber");
        String startDate = (String) params.get("startDate");
        String endDate = (String)params.get("endDate");
        String temp = (String)params.get("page");
        Integer pageNo = temp==null?0:Integer.parseInt(temp)-1;
        temp = (String) params.get("limit");
        Integer pageSize = temp==null?10:Integer.parseInt(temp);
        Page<SubAccountLingExchangeCNY> page = lingExchangeCNYDao.findAll(new Specification<SubAccountLingExchangeCNY>() {
            @Override
            public Predicate toPredicate(Root<SubAccountLingExchangeCNY> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                List<Predicate> list = new ArrayList<Predicate>();
                if(!StringUtils.isEmpty(realName)){
                    list.add(criteriaBuilder.like(root.get("realName").as(String.class), "%"+realName+"%"));
                }
                if (!StringUtils.isEmpty(mobileNumber)){
                    list.add(criteriaBuilder.like(root.get("mobileNumber").as(String.class),"%"+mobileNumber+"%"));
                }
                if (!StringUtils.isEmpty(startDate)){
                    list.add(criteriaBuilder.greaterThanOrEqualTo(root.get("createTime"), org.wk.core.common.tool.StringUtils.strToDate(startDate)));
                }
                if (!StringUtils.isEmpty(endDate)){
                    list.add(criteriaBuilder.lessThanOrEqualTo(root.get("createTime"), org.wk.core.common.tool.StringUtils.strToDate(endDate)));
                }
                /*if(null!=lingExchangeCNY.getMobileNumber()&&!"".equals(lingExchangeCNY.getMobileNumber())){
                    // 关键字条件查询
                    list.add(criteriaBuilder.or(criteriaBuilder.like(root.get("mobileNumber").as(String.class), "%"+lingExchangeCNY.getMobileNumber()+"%"),
                            criteriaBuilder.like(root.get("realName").as(String.class), "%"+lingExchangeCNY.getMobileNumber()+"%")));
                }*/
                // 查询刚提交的提现申请
                list.add(criteriaBuilder.equal(root.get("exchangeStatusCode").as(String.class), ExchangeCNYStatus.NOT_EXCHANGE_CNY.getCode()));
                Predicate[] p = new Predicate[list.size()];
                return criteriaBuilder.and(list.toArray(p));
            }
        }, PageRequest.of(pageNo,pageSize,new Sort(Sort.Direction.DESC,"createTime")));

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        List<LingExchangeCNYVo> result = new ArrayList<>();
        for (SubAccountLingExchangeCNY subAccountLingExchangeCNY: page.getContent() ) {
            LingExchangeCNYVo lingExchangeCNYVo = new LingExchangeCNYVo();
            BeanUtils.copyProperties(subAccountLingExchangeCNY, lingExchangeCNYVo);
            lingExchangeCNYVo.setCreateTime(sdf.format(subAccountLingExchangeCNY.getCreateTime()));
            result.add(lingExchangeCNYVo);
        }
        PageVo pageVo = new PageVo<LingExchangeCNYVo>();
        pageVo.setTotal(page.getTotalElements());
        pageVo.setPageNo(++pageNo);
        pageVo.setPageSize(pageSize);
        pageVo.setResult(result);
        pageVo.setTotalPages(page.getTotalPages());
        return pageVo;
    }

    /*
     * @Description 鲸灵提取现金通过
     * @param id
     * @author ZhaoPing'an
     * @Date 2018/7/2 15:44
     */
    @Override
    public ResponseVo successExchangeCNY(String id) {
        SubAccountLingExchangeCNY entity = lingExchangeCNYDao.getOne(id);
        entity.setExchangeStatusCode(ExchangeCNYStatus.HAS_EXCHANGE_CNY.getCode());
        entity.setExchangeStatusName(ExchangeCNYStatus.HAS_EXCHANGE_CNY.getName());
        lingExchangeCNYDao.update(entity);

        String userId =  entity.getUserId();
        SubAccountLing subAccountLing = subAccountLingDao.findByUserId(userId);
        // 当前账户鲸灵金额
        BigDecimal preAmount = subAccountLing.getAmount();
        // 变动后金额
        BigDecimal afterExchangeAmount = preAmount.subtract(entity.getAmount());
        // 更新鲸灵账户金额
        subAccountLing.setAmount(afterExchangeAmount);
        subAccountLing.setUserId(userId);
        subAccountLingDao.saveOrUpdate(subAccountLing);
        // 保存鲸灵变动记录
        SubAccountLingSeq subAccountLingSeq = new SubAccountLingSeq();
        subAccountLingSeq.setUserId(userId);
        subAccountLingSeq.setAmount(afterExchangeAmount);
        subAccountLingSeq.setPreAmount(preAmount);
        subAccountLingSeq.setChangeAmount(entity.getAmount());
        subAccountLingSeq.setSeqFlagCode(SeqFlag.EXPEND.getCode());
        subAccountLingSeq.setSeqFlagName(SeqFlag.EXPEND.getName());
        subAccountLingSeq.setChangeTypeCode(LingChangeType.EXCHANGE_CNY.getCode());
        subAccountLingSeq.setChangeTypeName(LingChangeType.EXCHANGE_CNY.getName());
        subAccountLingSeqDao.save(subAccountLingSeq);
        // 更新用户总账户鲸灵金额
        SubAccount subAccount = subAccountDao.findByUserIdAndAccountTypeCode(userId,AccountType.JING_LING.getCode());
        subAccount.setAmount(afterExchangeAmount);
        subAccountDao.update(subAccount);

        Map<String,String> pushExt = new HashMap<>();
        pushExt.put("content_type","sys_notice");
        Map<String,Object> content = new HashMap<>();
        content.put("title","系统通知");
        content.put("content","你好，您的鲸灵提现已经成功！");
        pushExt.put("content",JSONObject.toJSONString(content));
        // 推送？ 短信？
        pushService.pushNotification("提现成功",pushExt,userId);
        return ResponseVo.success();
    }

    /*
     * @Description 鲸灵提取现金拒绝
     * @param
     * @author ZhaoPing'an
     * @Date 2018/7/3 14:17
     */
    @Override
    public ResponseVo refuseExchangeCNY(LingExchangeCNYVo lingExchangeCNY) {
        SubAccountLingExchangeCNY entity = lingExchangeCNYDao.getOne(lingExchangeCNY.getId());
        entity.setExchangeStatusCode(ExchangeCNYStatus.REFUSE_EXCHANGE_CNY.getCode());
        entity.setExchangeStatusName(ExchangeCNYStatus.REFUSE_EXCHANGE_CNY.getName());
        entity.setReason(lingExchangeCNY.getReason());
        lingExchangeCNYDao.update(entity);
        // 通知？
        Map<String,String> pushExt = new HashMap<>();
        pushExt.put("content_type","sys_notice");
        Map<String,Object> content = new HashMap<>();
        content.put("title","系统通知");
        content.put("content","你好，您的鲸灵提现失败，原因："+lingExchangeCNY.getReason());
        pushExt.put("content",JSONObject.toJSONString(content));
        // 推送？ 短信？
        pushService.pushNotification("提现失败",pushExt,entity.getUserId());
        return ResponseVo.success();
    }

    /*
     * @Description 鲸灵提现记录列表
     * @param
     * @author ZhaoPing'an
     * @Date 2018/7/4 14:45
     */
    @Override
    public PageVo findExchangeCNYSeq(Map<String, Object> params) {
        String realName = (String)params.get("realName");
        String mobileNumber = (String)params.get("mobileNumber");
        String startDate = (String) params.get("startDate");
        String endDate = (String)params.get("endDate");
        String temp = (String)params.get("page");
        Integer pageNo = temp==null?0:Integer.parseInt(temp)-1;
        temp = (String) params.get("limit");
        Integer pageSize = temp==null?10:Integer.parseInt(temp);
        Page<SubAccountLingExchangeCNY> page = lingExchangeCNYDao.findAll(new Specification<SubAccountLingExchangeCNY>() {
            @Override
            public Predicate toPredicate(Root<SubAccountLingExchangeCNY> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                List<Predicate> list = new ArrayList<Predicate>();
                if(!StringUtils.isEmpty(realName)){
                    list.add(criteriaBuilder.like(root.get("realName").as(String.class), "%"+realName+"%"));
                }
                if (!StringUtils.isEmpty(mobileNumber)){
                    list.add(criteriaBuilder.like(root.get("mobileNumber").as(String.class),"%"+mobileNumber+"%"));
                }
                if (!StringUtils.isEmpty(startDate)){
                    list.add(criteriaBuilder.greaterThanOrEqualTo(root.get("createTime"), org.wk.core.common.tool.StringUtils.strToDate(startDate)));
                }
                if (!StringUtils.isEmpty(endDate)){
                    list.add(criteriaBuilder.lessThanOrEqualTo(root.get("createTime"), org.wk.core.common.tool.StringUtils.strToDate(endDate)));
                }
                list.add(criteriaBuilder.notEqual(root.get("exchangeStatusCode").as(String.class), ExchangeCNYStatus.NOT_EXCHANGE_CNY.getCode()));
                /*if(null!=lingExchangeCNY.getMobileNumber()&&!"".equals(lingExchangeCNY.getMobileNumber())){
                    // 关键字条件查询
                    list.add(criteriaBuilder.or(criteriaBuilder.like(root.get("mobileNumber").as(String.class), "%"+lingExchangeCNY.getMobileNumber()+"%"),
                            criteriaBuilder.like(root.get("realName").as(String.class), "%"+lingExchangeCNY.getMobileNumber()+"%")));
                }*/
                Predicate[] p = new Predicate[list.size()];
                return criteriaBuilder.and(list.toArray(p));
            }
        }, PageRequest.of(pageNo,pageSize,new Sort(Sort.Direction.DESC,"createTime")));

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        List<LingExchangeCNYVo> result = new ArrayList<>();
        for (SubAccountLingExchangeCNY lingExchangeCNYSeq: page.getContent() ) {
            LingExchangeCNYVo lingExchangeCNYVo = new LingExchangeCNYVo();
            BeanUtils.copyProperties(lingExchangeCNYSeq, lingExchangeCNYVo);
            lingExchangeCNYVo.setCreateTime(sdf.format(lingExchangeCNYSeq.getCreateTime()));
            result.add(lingExchangeCNYVo);
        }
        PageVo pageVo = new PageVo<LingExchangeCNYVo>();
        pageVo.setTotal(page.getTotalElements());
        pageVo.setPageNo(++pageNo);
        pageVo.setPageSize(pageSize);
        pageVo.setResult(result);
        pageVo.setTotalPages(page.getTotalPages());
        return pageVo;
    }


    /*
     * @Description 精灵提现(手机端接口)
     * @param jsonObject
     * @author ZhaoPing'an
     * @Date 2018/6/27 15:30
     */
    @Override
    public ResponseVo lingExchangeCNY(JSONObject jsonObject) {
        String exchangecnyTypeCode = jsonObject.getString("exchangecnyTypeCode");
        // 真实姓名
        String realName = jsonObject.getString("real_name");
        // 收款账户（支付宝、银行卡？）
        String receiveAccount = jsonObject.getString("receive_account");
        // 提现金额
        BigDecimal quantity = jsonObject.getBigDecimal("quantity");
        // 手机号
        String mobileNumber = jsonObject.getString("mobile_number");
        String smsCode = jsonObject.getString("sms_code");
        // 数据校验
        if(Strings.isNullOrEmpty(exchangecnyTypeCode) || Strings.isNullOrEmpty(realName) || Strings.isNullOrEmpty(receiveAccount)
                || quantity==null || Strings.isNullOrEmpty(smsCode)) {
            return new ResponseVo(ResponseCode.COMPLETE_DATA);
        }
        // 手机号校验
        if (Strings.isNullOrEmpty(mobileNumber)||!RegexUtils.checkMobileNum(mobileNumber)) {
            return new ResponseVo(ResponseCode.MOBILE_NUMBER_ERROR);
        }
        // 验证码校验
        Sms sms = smsDao.findByMobileNumberAndSmsCodeTypeGreaterThanExpireTimeLimit1(mobileNumber,SmsCodeType.EXCHANGE_CNY.getCode(),new Date());
        if (null == sms || !smsCode.equals(sms.getSmsCode())) {
            return new ResponseVo(ResponseCode.SMS_CODE_ERROR);
        }
        String userId = WebUtils.getUser().getId();
        SubAccountLing subAccountLing = subAccountLingDao.findByUserId(userId);
        // 当前账户鲸灵金额
        BigDecimal preAmount = subAccountLing.getAmount();
        // 当前鲸灵账户余额校验
        if (quantity.compareTo(preAmount) > 0){
            return new ResponseVo(ResponseCode.AMOUNT_DATA_ERROR);
        }
        // 变动后金额
        BigDecimal afterExchangeAmount = preAmount.subtract(quantity);
        // 保存鲸灵提现申请
        SubAccountLingExchangeCNY subAccountLingExchangeCNY = new SubAccountLingExchangeCNY();
        subAccountLingExchangeCNY.setUserId(userId);
        subAccountLingExchangeCNY.setAmount(quantity);
        subAccountLingExchangeCNY.setRealName(realName);
        subAccountLingExchangeCNY.setMobileNumber(mobileNumber);
        subAccountLingExchangeCNY.setReceiveAccount(receiveAccount);
        subAccountLingExchangeCNY.setExchangecnyTypeCode(ExchangeCNYType.ALIPAY.getCode());
        subAccountLingExchangeCNY.setExchangecnyTypeName(ExchangeCNYType.ALIPAY.getName());
        subAccountLingExchangeCNY.setExchangeStatusCode(ExchangeCNYStatus.NOT_EXCHANGE_CNY.getCode());
        subAccountLingExchangeCNY.setExchangeStatusName(ExchangeCNYStatus.NOT_EXCHANGE_CNY.getName());
        lingExchangeCNYDao.save(subAccountLingExchangeCNY);
        /*// 更新鲸灵账户金额
        subAccountLing.setAmount(afterExchangeAmount);
        subAccountLing.setUserId(userId);
        subAccountLingDao.saveOrUpdate(subAccountLing);
        // 保存鲸灵变动记录
        SubAccountLingSeq subAccountLingSeq = new SubAccountLingSeq();
        subAccountLingSeq.setUserId(userId);
        subAccountLingSeq.setAmount(afterExchangeAmount);
        subAccountLingSeq.setPreAmount(preAmount);
        subAccountLingSeq.setChangeAmount(quantity);
        subAccountLingSeq.setSeqFlagCode(SeqFlag.INCOME.getCode());
        subAccountLingSeq.setSeqFlagName(SeqFlag.EXPEND.getName());
        subAccountLingSeq.setChangeTypeCode(LingChangeType.EXCHANGE_CNY.getCode());
        subAccountLingSeq.setChangeTypeName(LingChangeType.EXCHANGE_CNY.getName());
        subAccountLingSeqDao.save(subAccountLingSeq);
        // 更新用户总账户鲸灵金额
        SubAccount subAccount = subAccountDao.findByUserIdAndAccountTypeCode(userId,AccountType.JING_LING.getCode());
        subAccount.setAmount(afterExchangeAmount);
        subAccountDao.update(subAccount);*/
        return ResponseVo.success();
    }

    /*
     * @description 导出提现记录
     * @param
     * @author ZhaoPing'an
     * @date 2018/7/24 10:16
     */
    @Override
    public List<Object[]> exportSeqs(Map<String, Object> params,int size){
        List<SubAccountLingExchangeCNY> seqsData = lingExchangeCNYDao.findAll();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        List<Object[]>  datas = new ArrayList<Object[]>();
        for (int i = 0; i < seqsData.size(); i++) {
            SubAccountLingExchangeCNY data = seqsData.get(i);
            Object[] rowData = new Object[size];
            rowData[0] = i;
            rowData[1] = seqsData.get(i).getRealName();
            rowData[2] = seqsData.get(i).getMobileNumber();
            rowData[3] = seqsData.get(i).getExchangecnyTypeName();
            rowData[4] = seqsData.get(i).getAmount();
            rowData[5] = seqsData.get(i).getReceiveAccount();
            rowData[6] = seqsData.get(i).getExchangeStatusName();
            if (StringUtils.isEmpty(seqsData.get(i).getReason())){
                rowData[7] = "  ";
            } else {
                rowData[7] = seqsData.get(i).getReason();
            }
            rowData[8] = sdf.format(seqsData.get(i).getCreateTime());
            datas.add(rowData);
        }
        return datas;
    }

    @Override
    public void updateLingAccount(BigDecimal ling, String userId) {
        SubAccountLing subAccountLing = subAccountLingDao.findByUserId(userId);
        SubAccountLingSeq subAccountLingSeq = new SubAccountLingSeq();
        BigDecimal amount = subAccountLing.getAmount();
        BigDecimal changeAmount = new BigDecimal(0);
        int num = ling.compareTo(amount);
        if (num < 0){
            changeAmount = amount.subtract(ling);
            subAccountLingSeq.setSeqFlagCode(SeqFlag.EXPEND.getCode());
            subAccountLingSeq.setSeqFlagName(SeqFlag.EXPEND.getName());
        }
        if (num > 0){
            changeAmount = ling.subtract(amount);
            subAccountLingSeq.setSeqFlagCode(SeqFlag.INCOME.getCode());
            subAccountLingSeq.setSeqFlagName(SeqFlag.INCOME.getName());
        }
        if (num!=0 && ling.compareTo(new BigDecimal(0))>=0){
            SubAccountLingAdminUpdateBill adminUpdateBill = new SubAccountLingAdminUpdateBill();
            adminUpdateBill.setAmount(changeAmount);
            adminUpdateBill.setUserId(userId);
            subAccountLingAdminUpdateBillDao.save(adminUpdateBill);
            subAccountLing.setAmount(ling);
            subAccountLing.setUserId(userId);
            subAccountLingDao.saveOrUpdate(subAccountLing);
            subAccountLingSeq.setUserId(userId);
            subAccountLingSeq.setChangeTypeCode(BaoChangeType.ADMIN_UPDATE.getCode());
            subAccountLingSeq.setChangeTypeName(BaoChangeType.ADMIN_UPDATE.getName());
            subAccountLingSeq.setPreAmount(amount);
            subAccountLingSeq.setAmount(ling);
            subAccountLingSeq.setChangeAmount(changeAmount);
            subAccountLingSeqDao.save(subAccountLingSeq);
            SubAccount subAccount = subAccountDao.findByUserIdAndAccountTypeCode(userId, AccountType.JING_LING.getCode());
            subAccount.setAmount(ling);
            subAccountDao.update(subAccount);
        }
    }

    @Override
    public Page<SubAccountLingSeq> findSeqByUserIds(int pageNum, int pageSize, List<String> userIds) {
        Sort sort = Sort.by(Sort.Direction.DESC,"createTime");
        Page<SubAccountLingSeq> zaiSeqPage = subAccountLingSeqDao.findAll(new Specification<SubAccountLingSeq>() {
            @Override
            public Predicate toPredicate(Root<SubAccountLingSeq> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                List<Predicate> list = new ArrayList<Predicate>();
                if(!userIds.isEmpty()){
                    CriteriaBuilder.In<String> in = criteriaBuilder.in(root.get("userId"));
                    for (String userId:userIds){
                        in.value(userId);
                    }
                    list.add(in);
                }
                Predicate[] p = new Predicate[list.size()];
                return criteriaBuilder.and(list.toArray(p));
            }
        }, PageRequest.of(pageNum,pageSize,sort));
        return zaiSeqPage;
    }
}
